<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>可旋转3D立方体</title>
  <style>
    canvas {
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400"></canvas>
  <script>
    function sleep(milliseconds) {
      return new Promise(resolve => setTimeout(resolve, milliseconds));
    }
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    // 获取canvas的宽高
    const canvasWidth = canvas.width;
    const canvasHeight = canvas.height;

    // 3D场景参数
    const cubeSize = 150; // 立方体的大小
    const halfCanvasWidth = canvasWidth / 2;
    const halfCanvasHeight = canvasHeight / 2;
    const perspective = 500; // 投影距离

    class Face {
      constructor(points, color) {
        this.points = points;
        this.color = color;
      }
    }

    const frontFace = new Face(
      [
        { x: -cubeSize, y: -cubeSize, z: cubeSize },
        { x: cubeSize, y: -cubeSize, z: cubeSize },
        { x: cubeSize, y: cubeSize, z: cubeSize },
        { x: -cubeSize, y: cubeSize, z: cubeSize }
      ],
      '#f00'
    );

    const backFace = new Face(
      [
        { x: -cubeSize, y: -cubeSize, z: -cubeSize },
        { x: cubeSize, y: -cubeSize, z: -cubeSize },
        { x: cubeSize, y: cubeSize, z: -cubeSize },
        { x: -cubeSize, y: cubeSize, z: -cubeSize }
      ],
      '#0f0'
    );

    const topFace = new Face(
      [
        { x: -cubeSize, y: -cubeSize, z: -cubeSize },
        { x: cubeSize, y: -cubeSize, z: -cubeSize },
        { x: cubeSize, y: -cubeSize, z: cubeSize },
        { x: -cubeSize, y: -cubeSize, z: cubeSize }
      ],
      '#00f'
    );

    const bottomFace = new Face(
      [
        { x: -cubeSize, y: cubeSize, z: -cubeSize },
        { x: cubeSize, y: cubeSize, z: -cubeSize },
        { x: cubeSize, y: cubeSize, z: cubeSize },
        { x: -cubeSize, y: cubeSize, z: cubeSize }
      ],
      '#ff0'
    );

    const rightFace = new Face(
      [
        { x: cubeSize, y: -cubeSize, z: -cubeSize },
        { x: cubeSize, y: -cubeSize, z: cubeSize },
        { x: cubeSize, y: cubeSize, z: cubeSize },
        { x: cubeSize, y: cubeSize, z: -cubeSize }
      ],
      '#0ff'
    );

    const leftFace = new Face(
      [
        { x: -cubeSize, y: -cubeSize, z: -cubeSize },
        { x: -cubeSize, y: -cubeSize, z: cubeSize },
        { x: -cubeSize, y: cubeSize, z: cubeSize },
        { x: -cubeSize, y: cubeSize, z: -cubeSize }
      ],
      '#f0f'
    );

    const faces = [frontFace, backFace, topFace, bottomFace, rightFace, leftFace];

    function project(point) {
      const factor = perspective / (perspective + point.z);
      return {
        x: point.x * factor + halfCanvasWidth,
        y: point.y * factor + halfCanvasHeight
      };
    }

    function draw() {
      ctx.clearRect(0, 0, canvasWidth, canvasHeight);

      faces.forEach(face => {
        const projectedPoints = face.points.map(project);

        ctx.beginPath();

        ctx.moveTo(projectedPoints[0].x, projectedPoints[0].y);

        projectedPoints.forEach(point =>
          ctx.lineTo(point.x, point.y)
        );

        ctx.closePath();

        ctx.fillStyle = face.color;
        ctx.fill();
      });
    }

    function rotate(angleX, angleY, angleZ) {
      const radianX = angleX * Math.PI / 180;
      const radianY = angleY * Math.PI / 180;
      const radianZ = angleZ * Math.PI / 180;

      const cosX = Math.cos(radianX);
      const sinX = Math.sin(radianX);
      const cosY = Math.cos(radianY);
      const sinY = Math.sin(radianY);
      const cosZ = Math.cos(radianZ);
      const sinZ = Math.sin(radianZ);

      const matrix = [
        [cosY * cosZ, cosX * sinZ + sinX * sinY * cosZ, sinX * sinZ - cosX * sinY * cosZ],
        [-cosY * sinZ, cosX * cosZ - sinX * sinY * sinZ, sinX * cosZ + cosX * sinY * sinZ],
        [sinY, -sinX * cosY, cosX * cosY]
      ];

      faces.forEach(face => {
        face.points.forEach(point => {
          const x = point.x;
          const y = point.y;
          const z = point.z;

          point.x = x * matrix[0][0] + y * matrix[0][1] + z * matrix[0][2];
          point.y = x * matrix[1][0] + y * matrix[1][1] + z * matrix[1][2];
          point.z = x * matrix[2][0] + y * matrix[2][1] + z * matrix[2][2];
        });
      });
    }

    let angleX = 0;
    let angleY = 0;
    let angleZ = 0;

    async function loop() {
      await sleep(3000);
      draw();

      angleX += 1;
      angleY += 2;
      angleZ += 3;
      rotate(angleX, angleY, angleZ);

      requestAnimationFrame(loop);
    }

    loop();
  </script>
</body>
</html>

